package com.eksframework.commons.core.base;

import javax.annotation.Nullable;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.util.zip.*;

/**
 * Zip、GZip压缩、解压缩
 *
 * @author: chenfenghai
 * @version: 1.0
 * @date: 2020-05-11 16:07
 * @blame Team
 */
public class EksZip {

    /**
     * GZIP格式字符串前缀
     */
    private static final String GZIP_STRING_PREFIX = "H4sIAAAA";

    /**
     * Constructor.
     */
    EksZip(){
    }

    /**
     * 使用gzip进行压缩
     *
     * @param uncompressed 未压缩字符串
     * @return 已压缩字符串
     */
    @Nullable
    public static String gzip(@Nullable final String uncompressed) {
        if (uncompressed == null || uncompressed.length() == 0) {
            return uncompressed;
        }
        try (
                ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
                GZIPOutputStream gzipOutputStream = new GZIPOutputStream(byteArrayOutputStream);
        ) {
            gzipOutputStream.write(uncompressed.getBytes());
            return new sun.misc.BASE64Encoder().encode(byteArrayOutputStream.toByteArray());
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }

    /**
     * 使用gzip进行解压缩
     *
     * @param compressed 已压缩字符串
     * @return 解压缩后字符串
     */
    @Nullable
    public static String ungzip(@Nullable final String compressed) {
        if (compressed == null || compressed.length() == 0) {
            return compressed;
        }
        try (ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream()) {
            byte[] bytes = new sun.misc.BASE64Decoder().decodeBuffer(compressed);
            try (
                    ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(bytes);
                    GZIPInputStream gzipInputStream = new GZIPInputStream(byteArrayInputStream)
            ) {
                int offset;
                byte[] buffer = new byte[1024];
                while ((offset = gzipInputStream.read(buffer)) != -1) {
                    byteArrayOutputStream.write(buffer, 0, offset);
                }
                return byteArrayOutputStream.toString();
            }
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }

    /**
     * 使用zip进行压缩
     *
     * @param uncompressed 压缩前的文本
     * @return 压缩后的文本
     */
    @Nullable
    public static String zip(@Nullable final String uncompressed) {
        if (uncompressed == null || uncompressed.length() == 0) {
            return uncompressed;
        }
        try (
                ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
                ZipOutputStream zipOutputStream = new ZipOutputStream(outputStream)
        ) {
            zipOutputStream.putNextEntry(new ZipEntry("0"));
            zipOutputStream.write(uncompressed.getBytes());
            zipOutputStream.closeEntry();
            return new sun.misc.BASE64Encoder().encodeBuffer(outputStream.toByteArray());
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }

    /**
     * 使用zip进行解压缩
     *
     * @param compressed 压缩后的文本
     * @return 解压后的字符串
     */
    @Nullable
    public static String unzip(@Nullable final String compressed) {
        if (compressed == null || compressed.length() == 0) {
            return compressed;
        }
        try {
            byte[] bytes = new sun.misc.BASE64Decoder().decodeBuffer(compressed);
            try (
                    ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
                    ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(bytes);
                    ZipInputStream zipInputStream = new ZipInputStream(byteArrayInputStream)
            ) {
                int offset;
                zipInputStream.getNextEntry();
                byte[] buffer = new byte[1024];
                while ((offset = zipInputStream.read(buffer)) != -1) {
                    byteArrayOutputStream.write(buffer, 0, offset);
                }
                return byteArrayOutputStream.toString();
            }
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }

    /**
     * 是否GZIP格式字符串
     *
     * @param string 字符串
     * @return boolean
     */
    public static boolean isGzipString(@Nullable String string) {
        return string != null && string.startsWith(GZIP_STRING_PREFIX);
    }
}
